From: Jeroen van der Heijden Date: Thu, 9 Jan 2020 10:01:13 +0000 (+0100) Subject: Working example, no json query X-Git-Tag: archive/raspbian/2.0.44-1+rpi1~1^2~3^2~5^2~37 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=1afcecf471093b386b3ba46a3fd588476128b6c5;p=siridb-server.git Working example, no json query --- diff --git a/Debug/makefile b/Debug/makefile index e700a330..c43b8139 100644 --- a/Debug/makefile +++ b/Debug/makefile @@ -4,6 +4,7 @@ RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk +-include src/base64/subdir.mk -include src/xpath/subdir.mk -include src/xmath/subdir.mk -include src/timeit/subdir.mk @@ -20,6 +21,7 @@ RM := rm -rf -include src/siri/args/subdir.mk -include src/siri/subdir.mk -include src/qpack/subdir.mk +-include src/qpjson/subdir.mk -include src/procinfo/subdir.mk -include src/owcrypt/subdir.mk -include src/motd/subdir.mk diff --git a/Debug/sources.mk b/Debug/sources.mk index 0e90c356..35930d3f 100644 --- a/Debug/sources.mk +++ b/Debug/sources.mk @@ -11,6 +11,7 @@ C_DEPS := SUBDIRS := \ . \ src/argparse \ +src/base64 \ src/cexpr \ src/cfgparser \ src/ctree \ @@ -24,6 +25,7 @@ src/logger \ src/owcrypt \ src/procinfo \ src/qpack \ +src/qpjson \ src/siri/service \ src/siri/args \ src/siri \ diff --git a/Debug/src/base64/subdir.mk b/Debug/src/base64/subdir.mk new file mode 100644 index 00000000..e9ad5837 --- /dev/null +++ b/Debug/src/base64/subdir.mk @@ -0,0 +1,20 @@ +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/base64/base64.c + +OBJS += \ +./src/base64/base64.o + +C_DEPS += \ +./src/base64/base64.d + + +# Each subdirectory must supply rules for building sources it contributes +src/base64/%.o: ../src/base64/%.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + gcc -I../include -O0 -g3 -Wall -Wextra $(CPPFLAGS) $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/Debug/src/qpjson/subdir.mk b/Debug/src/qpjson/subdir.mk new file mode 100644 index 00000000..5a0007c1 --- /dev/null +++ b/Debug/src/qpjson/subdir.mk @@ -0,0 +1,20 @@ +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/qpjson/qpjson.c + +OBJS += \ +./src/qpjson/qpjson.o + +C_DEPS += \ +./src/qpjson/qpjson.d + + +# Each subdirectory must supply rules for building sources it contributes +src/qpjson/%.o: ../src/qpjson/%.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + gcc -I../include -O0 -g3 -Wall -Wextra $(CPPFLAGS) $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/Debug/src/siri/subdir.mk b/Debug/src/siri/subdir.mk index 1e4e9bb5..0ee94fb2 100644 --- a/Debug/src/siri/subdir.mk +++ b/Debug/src/siri/subdir.mk @@ -1,5 +1,6 @@ # Add inputs and outputs from these tool invocations to the build variables C_SRCS += \ +../src/siri/api.c \ ../src/siri/async.c \ ../src/siri/backup.c \ ../src/siri/buffersync.c \ @@ -11,6 +12,7 @@ C_SRCS += \ ../src/siri/version.c OBJS += \ +./src/siri/api.o \ ./src/siri/async.o \ ./src/siri/backup.o \ ./src/siri/buffersync.o \ @@ -22,6 +24,7 @@ OBJS += \ ./src/siri/version.o C_DEPS += \ +./src/siri/api.d \ ./src/siri/async.d \ ./src/siri/backup.d \ ./src/siri/buffersync.d \ diff --git a/Release/makefile b/Release/makefile index d6ca27fd..cb978b7b 100644 --- a/Release/makefile +++ b/Release/makefile @@ -4,6 +4,7 @@ RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk +-include src/base64/subdir.mk -include src/xpath/subdir.mk -include src/xmath/subdir.mk -include src/timeit/subdir.mk @@ -20,6 +21,7 @@ RM := rm -rf -include src/siri/args/subdir.mk -include src/siri/subdir.mk -include src/qpack/subdir.mk +-include src/qpjson/subdir.mk -include src/procinfo/subdir.mk -include src/owcrypt/subdir.mk -include src/motd/subdir.mk diff --git a/Release/sources.mk b/Release/sources.mk index 0e90c356..35930d3f 100644 --- a/Release/sources.mk +++ b/Release/sources.mk @@ -11,6 +11,7 @@ C_DEPS := SUBDIRS := \ . \ src/argparse \ +src/base64 \ src/cexpr \ src/cfgparser \ src/ctree \ @@ -24,6 +25,7 @@ src/logger \ src/owcrypt \ src/procinfo \ src/qpack \ +src/qpjson \ src/siri/service \ src/siri/args \ src/siri \ diff --git a/Release/src/base64/subdir.mk b/Release/src/base64/subdir.mk new file mode 100644 index 00000000..31aeb9c5 --- /dev/null +++ b/Release/src/base64/subdir.mk @@ -0,0 +1,20 @@ +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/base64/base64.c + +OBJS += \ +./src/base64/base64.o + +C_DEPS += \ +./src/base64/base64.d + + +# Each subdirectory must supply rules for building sources it contributes +src/base64/%.o: ../src/base64/%.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + gcc -DNDEBUG -I../include -O3 -Wall -Wextra $(CPPFLAGS) $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/Release/src/qpjson/subdir.mk b/Release/src/qpjson/subdir.mk new file mode 100644 index 00000000..515d5b6f --- /dev/null +++ b/Release/src/qpjson/subdir.mk @@ -0,0 +1,20 @@ +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/qpjson/qpjson.c + +OBJS += \ +./src/qpjson/qpjson.o + +C_DEPS += \ +./src/qpjson/qpjson.d + + +# Each subdirectory must supply rules for building sources it contributes +src/qpjson/%.o: ../src/qpjson/%.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + gcc -DNDEBUG -I../include -O3 -Wall -Wextra $(CPPFLAGS) $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/Release/src/siri/subdir.mk b/Release/src/siri/subdir.mk index e29641de..d22d9d8a 100644 --- a/Release/src/siri/subdir.mk +++ b/Release/src/siri/subdir.mk @@ -1,5 +1,6 @@ # Add inputs and outputs from these tool invocations to the build variables C_SRCS += \ +../src/siri/api.c \ ../src/siri/async.c \ ../src/siri/backup.c \ ../src/siri/buffersync.c \ @@ -11,6 +12,7 @@ C_SRCS += \ ../src/siri/version.c OBJS += \ +./src/siri/api.o \ ./src/siri/async.o \ ./src/siri/backup.o \ ./src/siri/buffersync.o \ @@ -22,6 +24,7 @@ OBJS += \ ./src/siri/version.o C_DEPS += \ +./src/siri/api.d \ ./src/siri/async.d \ ./src/siri/backup.d \ ./src/siri/buffersync.d \ diff --git a/include/qpjson/qpjson.h b/include/qpjson/qpjson.h index b83a9345..629e05e0 100644 --- a/include/qpjson/qpjson.h +++ b/include/qpjson/qpjson.h @@ -17,7 +17,7 @@ enum yajl_gen_status qpjson_qp_to_json( - const void * src, + void * src, size_t src_n, unsigned char ** dst, size_t * dst_n, diff --git a/include/siri/api.h b/include/siri/api.h index 901575f2..09551e1f 100644 --- a/include/siri/api.h +++ b/include/siri/api.h @@ -6,14 +6,7 @@ #include #include - - -typedef enum -{ - SIRIDB_API_STATE_NONE, - SIRIDB_API_STATE_CONTENT_TYPE, - SIRIDB_API_STATE_AUTHORIZATION, -} siridb_api_state_t; +#include typedef enum { @@ -21,43 +14,27 @@ typedef enum SIRIDB_API_CT_JSON, } siridb_api_content_t; -typedef enum -{ - SIRIDB_API_FLAG_IS_CLOSED =1<<0, - SIRIDB_API_FLAG_IN_USE =1<<1, - SIRIDB_API_FLAG_JSON_BEAUTY =1<<2, - SIRIDB_API_FLAG_JSON_UTF8 =1<<3, -} siridb_api_flags_t; - typedef struct siri_api_request_s siri_api_request_t; +typedef int (*on_state_cb_t)(siri_api_request_t * ar, const char * at, size_t n); + int siri_api_init(void); -void siri_ali_close(siri_api_request_t * web_request); -static inline _Bool siri_api_is_handle(uv_handle_t * handle); +int siri_api_send(siri_api_request_t * ar, unsigned char * src, size_t n); struct siri_api_request_s { uint32_t tp; /* maps to siridb_tee_t flags for cleanup */ uint32_t ref; - on_data_cb_t on_data; + on_state_cb_t on_state; siridb_t * siridb; void * origin; /* can be a user, server or NULL */ char * buf; size_t len; size_t size; uv_stream_t * stream; - siridb_api_flags_t flags; - siridb_api_state_t state; siridb_api_content_t content_type; http_parser parser; + uv_write_t req; }; -static inline _Bool siri_api_is_handle(uv_handle_t * handle) -{ - return - handle->type == UV_TCP && - handle->data && - (((siri_api_request_t *) handle->data)->ref_ & SIRIDB_API_FLAG); -} - #endif /* SIRI_API_H_ */ diff --git a/include/siri/db/db.h b/include/siri/db/db.h index 0b183cd9..b5b5a3fe 100644 --- a/include/siri/db/db.h +++ b/include/siri/db/db.h @@ -44,6 +44,7 @@ int8_t siridb_get_idle_percentage(siridb_t * siridb); int siridb_is_db_path(const char * dbpath); siridb_t * siridb_new(const char * dbpath, int lock_flags); siridb_t * siridb_get(llist_t * siridb_list, const char * dbname); +siridb_t * siridb_getn(llist_t * siridb_list, const char * dbname, size_t n); siridb_t * siridb_get_by_qp(llist_t * siridb_list, qp_obj_t * qp_dbname); int siridb_decref_cb(siridb_t * siridb, void * args); ssize_t siridb_get_file(char ** buffer, siridb_t * siridb); diff --git a/include/siri/version.h b/include/siri/version.h index c1ff0cac..36fc2750 100644 --- a/include/siri/version.h +++ b/include/siri/version.h @@ -15,7 +15,7 @@ * Note that debian alpha packages should use versions like this: * 2.0.34-0alpha0 */ -#define SIRIDB_VERSION_PRE_RELEASE "-alpha-1" +#define SIRIDB_VERSION_PRE_RELEASE "-alpha-2" #ifndef NDEBUG #define SIRIDB_VERSION_BUILD_RELEASE "+debug" diff --git a/itest/test_http_api.py b/itest/test_http_api.py new file mode 100644 index 00000000..dfe40749 --- /dev/null +++ b/itest/test_http_api.py @@ -0,0 +1,16 @@ +import requests +import json + +data = { + 'q': 'select * from *' +} + +x = requests.post( + f'http://localhost:9020/query/dbtest', + data=json.dumps(data), + auth=('iris', 'siri'), + headers={'Content-Type': 'application/json'} +) + + +print(x.content) \ No newline at end of file diff --git a/src/qpjson/qpjson.c b/src/qpjson/qpjson.c index 76eff9af..da854953 100644 --- a/src/qpjson/qpjson.c +++ b/src/qpjson/qpjson.c @@ -1,12 +1,182 @@ /* * qpjson.c - Convert between QPack and JSON */ - +#include #include +#include -yajl_gen_status mpjson_mp_to_json( - const void * src, +static yajl_gen_status qp__to_json(yajl_gen g, qp_unpacker_t * up, qp_obj_t * obj) +{ + switch (obj->tp) + { + case QP_ERR: + case QP_ARRAY_CLOSE: + case QP_MAP_CLOSE: + case QP_END: + /* END, ARRAY_CLOSE and MAP_CLOSE should never occur since they can + * only happen after "*OPEN", and this case is handled in the *OPEN + * parts itself + */ + return yajl_gen_in_error_state; + case QP_INT64: + return yajl_gen_integer(g, obj->via.int64); + case QP_DOUBLE: + return yajl_gen_double(g, obj->via.real); + case QP_RAW: + return yajl_gen_string( + g, (unsigned char *) obj->via.raw, obj->len); + case QP_TRUE: + return yajl_gen_bool(g, 1 /* true */); + case QP_FALSE: + return yajl_gen_bool(g, 0 /* false */); + case QP_NULL: + return yajl_gen_null(g); + case QP_ARRAY0: + case QP_ARRAY1: + case QP_ARRAY2: + case QP_ARRAY3: + case QP_ARRAY4: + case QP_ARRAY5: + { + size_t i = obj->tp - QP_ARRAY0; + + yajl_gen_status stat; + if ((stat = yajl_gen_array_open(g)) != yajl_gen_status_ok) + return stat; + + while (i--) + { + qp_next(up, obj); + if ((stat = qp__to_json(g, up, obj)) != yajl_gen_status_ok) + return stat; + } + + return yajl_gen_array_close(g); + } + case QP_MAP0: + case QP_MAP1: + case QP_MAP2: + case QP_MAP3: + case QP_MAP4: + case QP_MAP5: + { + size_t i = obj->tp - QP_MAP0; + yajl_gen_status stat; + if ((stat = yajl_gen_map_open(g)) != yajl_gen_status_ok) + return stat; + + while (i--) + { + qp_next(up, obj); + if ((stat = qp__to_json(g, up, obj)) != yajl_gen_status_ok) + return stat; + + qp_next(up, obj); + if ((stat = qp__to_json(g, up, obj)) != yajl_gen_status_ok) + return stat; + } + + return yajl_gen_map_close(g); + } + case QP_ARRAY_OPEN: + { + yajl_gen_status stat; + if ((stat = yajl_gen_array_open(g)) != yajl_gen_status_ok) + return stat; + + while(qp_next(up, obj) && obj->tp != QP_ARRAY_CLOSE) + { + if ((stat = qp__to_json(g, up, obj)) != yajl_gen_status_ok) + return stat; + } + + return yajl_gen_array_close(g); + } + case QP_MAP_OPEN: + { + yajl_gen_status stat; + if ((stat = yajl_gen_map_open(g)) != yajl_gen_status_ok) + return stat; + + while(qp_next(up, obj) && obj->tp != QP_MAP_CLOSE) + { + if ((stat = qp__to_json(g, up, obj)) != yajl_gen_status_ok) + return stat; + + qp_next(up, obj); + if ((stat = qp__to_json(g, up, obj)) != yajl_gen_status_ok) + return stat; + } + return yajl_gen_map_close(g); + } + } + return yajl_gen_in_error_state; +} + + +yajl_gen_status qpjson_qp_to_json( + void * src, size_t src_n, unsigned char ** dst, size_t * dst_n, int flags) +{ + qp_unpacker_t up; + qp_obj_t obj; + yajl_gen g; + yajl_status stat; + + assert (src_n); + qp_unpacker_init(&up, src, src_n); + + g = yajl_gen_alloc(NULL); + if (!g) + return yajl_gen_in_error_state; + + yajl_gen_config(g, yajl_gen_beautify, flags & QPJSON_FLAG_BEAUTIFY); + yajl_gen_config(g, yajl_gen_validate_utf8, flags & QPJSON_FLAG_VALIDATE_UTF8); + + qp_next(&up, &obj); + + assert (obj.tp != QP_END); + + if ((stat = qp__to_json(g, &up, &obj)) == yajl_status_ok) + { + const unsigned char * tmp; + yajl_gen_get_buf(g, &tmp, dst_n); + *dst = malloc(*dst_n); + if (*dst) + memcpy(*dst, tmp, *dst_n); + else + stat = yajl_gen_in_error_state; + } + + yajl_gen_free(g); + return stat; +} + + +yajl_status qpjson_json_to_qp( + const void * src, + size_t src_n, + char ** dst, + size_t * dst_n) +{ + yajl_handle hand; + yajl_status stat = yajl_status_error; + qp_packer_t * packer = qp_packer_new(src_n); + if (!packer) + return stat; + +// hand = yajl_alloc(&callbacks, NULL, c); +// if (!hand) +// goto fail1; +// +// stat = yajl_parse(hand, src, src_n); +// if (stat == yajl_status_ok) +// take_buffer(&buffer, dst, dst_n); +// yajl_free(hand); + + qp_packer_free(packer); + return stat; +} diff --git a/src/siri/api.c b/src/siri/api.c index 1f30e6c1..58e9523e 100644 --- a/src/siri/api.c +++ b/src/siri/api.c @@ -2,7 +2,11 @@ * api.c */ #include +#include #include +#include +#include +#include #define API__HEADER_MAX_SZ 256 #define CONTENT_TYPE_JSON "application/json" @@ -10,6 +14,9 @@ static uv_tcp_t api__uv_server; static http_parser_settings api__settings; +#define API__ICMP_WITH(__s, __n, __w) \ + __n == strlen(__w) && strncasecmp(__s, __w, __n) == 0 + static const char api__content_type[2][20] = { "text/plain", "application/json", @@ -49,6 +56,24 @@ typedef enum E503_SERVICE_UNAVAILABLE } api__header_t; +inline static int api__header( + char * ptr, + const api__header_t ht, + const siridb_api_content_t ct, + size_t content_length) +{ + int len = sprintf( + ptr, + "HTTP/1.1 %s\r\n" \ + "Content-Type: %s\r\n" \ + "Content-Length: %zu\r\n" \ + "\r\n", + api__html_header[ht], + api__content_type[ct], + content_length); + return len; +} + static inline _Bool api__starts_with( const char ** str, size_t * strn, @@ -56,15 +81,17 @@ static inline _Bool api__starts_with( size_t withn) { if (*strn < withn || strncasecmp(*str, with, withn)) + { return false; + } *str += withn; *strn -= withn; return true; } static void api__alloc_cb( - uv_handle_t * UNUSED(handle), - size_t UNUSED(sugsz), + uv_handle_t * UNUSED_handle __attribute__((unused)), + size_t UNUSED_sugsz __attribute__((unused)), uv_buf_t * buf) { buf->base = malloc(HTTP_MAX_HEADER_SIZE); @@ -79,7 +106,7 @@ static void api__data_cb( size_t parsed; siri_api_request_t * ar = uvstream->data; - if (ar->flags & SIRIDB_API_FLAG_IS_CLOSED) + if (!ar->ref) goto done; if (n < 0) @@ -87,7 +114,6 @@ static void api__data_cb( if (n != UV_EOF) log_error(uv_strerror(n)); - ar->flags |= SIRIDB_API_FLAG_IS_CLOSED; sirinet_stream_decref(ar); goto done; } @@ -107,7 +133,6 @@ static void api__data_cb( else if (parsed != (size_t) n) { log_warning("error parsing HTTP API request"); - ar->flags |= SIRIDB_API_FLAG_IS_CLOSED; sirinet_stream_decref(ar); } @@ -123,8 +148,9 @@ static int api__headers_complete_cb(http_parser * parser) ar->buf = malloc(parser->content_length); if (ar->len) + { ar->len = parser->content_length; - + } return 0; } @@ -132,7 +158,14 @@ static int api__url_cb(http_parser * parser, const char * at, size_t n) { siri_api_request_t * ar = parser->data; - + if (api__starts_with(&at, &n, "/query/", strlen("/query/"))) + { + ar->siridb = siridb_getn(siri.siridb_list, at, n); + if (ar->siridb) + { + siridb_incref(ar->siridb); + } + } return 0; } @@ -166,7 +199,8 @@ static void api__connection_cb(uv_stream_t * server, int status) } ar->tp = STREAM_API_CLIENT; - ar->on_data = NULL; + ar->ref = 1; + ar->on_state = NULL; (void) uv_tcp_init(siri.loop, (uv_tcp_t *) ar->stream); @@ -177,7 +211,7 @@ static void api__connection_cb(uv_stream_t * server, int status) if (rc) { log_error("cannot accept HTTP API request: `%s`", uv_strerror(rc)); - ti_api_close(ar); + sirinet_stream_decref(ar); return; } @@ -187,78 +221,68 @@ static void api__connection_cb(uv_stream_t * server, int status) if (rc) { log_error("cannot read HTTP API request: `%s`", uv_strerror(rc)); - ti_api_close(ar); + sirinet_stream_decref(ar); return; } } -static int api__header_field_cb(http_parser * parser, const char * at, size_t n) +static int api__on_content_type(siri_api_request_t * ar, const char * at, size_t n) { - siri_api_request_t * ar = parser->data; - - if (API__ICMP_WITH(at, n, "content-type")) + if (API__ICMP_WITH(at, n, CONTENT_TYPE_JSON)) { - ar->state = SIRIDB_API_STATE_CONTENT_TYPE; + ar->content_type = SIRIDB_API_CT_JSON; return 0; } - if (API__ICMP_WITH(at, n, "authorization")) + if (API__ICMP_WITH(at, n, "text/json")) { - ar->state = SIRIDB_API_STATE_AUTHORIZATION; + ar->content_type = SIRIDB_API_CT_JSON; return 0; } - ar->state = SIRIDB_API_STATE_NONE; + /* invalid content type */ + log_debug("unsupported content-type: %.*s", (int) n, at); return 0; } -static int api__header_value_cb(http_parser * parser, const char * at, size_t n) +static int api__on_authorization(siri_api_request_t * ar, const char * at, size_t n) { - siri_api_request_t * ar = parser->data; + if (api__starts_with(&at, &n, "token ", strlen("token "))) + { + log_debug("token authorization is not supported yet"); + } - switch (ar->state) + if (api__starts_with(&at, &n, "basic ", strlen("basic "))) { - case SIRIDB_API_STATE_NONE: - break; + siridb_user_t * user; + user = siridb_users_get_user_from_basic(ar->siridb, at, n); - case SIRIDB_API_STATE_CONTENT_TYPE: - if (API__ICMP_WITH(at, n, CONTENT_TYPE_JSON)) + if (user) { - ar->content_type = SIRIDB_API_CT_JSON; - break; + siridb_user_incref(user); + ar->origin = user; } - if (API__ICMP_WITH(at, n, "text/json")) - { - ar->content_type = SIRIDB_API_CT_JSON; - break; - } - - /* invalid content type */ - log_debug("unsupported content-type: %.*s", (int) n, at); - break; + return 0; + } - case SIRIDB_API_STATE_AUTHORIZATION: - if (api__starts_with(&at, &n, "token ", strlen("token "))) - { - log_debug("token authorization is not supported yet"); - } + log_debug("invalid authorization type: %.*s", (int) n, at); + return 0; +} +static int api__header_value_cb(http_parser * parser, const char * at, size_t n) +{ + siri_api_request_t * ar = parser->data; + return ar->on_state ? ar->on_state(ar, at, n) : 0; +} - if (api__starts_with(&at, &n, "basic ", strlen("basic "))) - { - siridb_user_t * user; - user = siridb_users_get_user_from_basic(ar->siridb, at, n); - - if (user) - { - siridb_user_incref(user); - ar->origin = user; - } - break; - } +static int api__header_field_cb(http_parser * parser, const char * at, size_t n) +{ + siri_api_request_t * ar = parser->data; - log_debug("invalid authorization type: %.*s", (int) n, at); - break; - } + ar->on_state = API__ICMP_WITH(at, n, "content-type") + ? api__on_content_type + : API__ICMP_WITH(at, n, "authorization") + ? api__on_authorization + : NULL; return 0; } @@ -285,7 +309,6 @@ static void api__write_cb(uv_write_t * req, int status) uv_strerror(status)); sirinet_stream_decref((siri_api_request_t *) req->handle->data); - free(req); } static int api__plain_response(siri_api_request_t * ar, const api__header_t ht) @@ -298,8 +321,6 @@ static int api__plain_response(siri_api_request_t * ar, const api__header_t ht) body_size = strlen(body); header_size = api__header(header, ht, SIRIDB_API_CT_TEXT, body_size); - uv_write_t * req = malloc(sizeof(uv_write_t)); - if (header_size > 0) { uv_buf_t uvbufs[2] = { @@ -307,12 +328,25 @@ static int api__plain_response(siri_api_request_t * ar, const api__header_t ht) uv_buf_init((char *) body, body_size), }; - (void) uv_write(req, ar->stream, uvbufs, 2, api__write_cb); + (void) uv_write(&ar->req, ar->stream, uvbufs, 2, api__write_cb); return 0; } return -1; } +static int api__query(siri_api_request_t * ar) +{ + const char q[100] = "select * from 'aggr'"; + + siridb_query_run( + 0, + (sirinet_stream_t *) ar, + q, strlen(q), + 0.0, + SIRIDB_QUERY_FLAG_MASTER); + return 0; +} + static int api__message_complete_cb(http_parser * parser) { siri_api_request_t * ar = parser->data; @@ -325,17 +359,11 @@ static int api__message_complete_cb(http_parser * parser) switch (ar->content_type) { + case SIRIDB_API_CT_TEXT: + /* Or, shall we allow text and return we some sort of CSV format? */ + return api__plain_response(ar, E400_BAD_REQUEST); case SIRIDB_API_CT_JSON: - { - char * data; - size_t size; - if (qpjson_json_to_qp(ar->buf, ar->len, &data, &size)) - return api__plain_response(ar, E400_BAD_REQUEST); - - free(ar->buf); - ar->buf = data; - ar->len = size; - } + return api__query(ar); } return api__plain_response(ar, E500_INTERNAL_SERVER_ERROR); @@ -353,6 +381,31 @@ static int api__chunk_complete_cb(http_parser * parser) return 0; } +static void api__write_free_cb(uv_write_t * req, int status) +{ + free(req->data); + api__write_cb(req, status); +} + +static int api__close_resp(siri_api_request_t * ar, void * data, size_t size) +{ + char header[API__HEADER_MAX_SZ]; + int header_size = 0; + + header_size = api__header(header, E200_OK, ar->content_type, size); + + uv_buf_t uvbufs[2] = { + uv_buf_init(header, (unsigned int) header_size), + uv_buf_init(data, size), + }; + + /* bind response to request to we can free in the callback */ + ar->req.data = data; + + uv_write(&ar->req, ar->stream, uvbufs, 2, api__write_free_cb); + return 0; +} + int siri_api_init(void) { int rc; @@ -393,3 +446,36 @@ int siri_api_init(void) log_info("start listening for HTTP API requests on TCP port %u", port); return 0; } + +int siri_api_send(siri_api_request_t * ar, unsigned char * src, size_t n) +{ + unsigned char * data; + if (ar->content_type == SIRIDB_API_CT_JSON) + { + size_t tmp_sz; + yajl_gen_status stat = qpjson_qp_to_json( + src, + n, + &data, + &tmp_sz, + 0); + if (stat) + { + // api__set_yajl_gen_status_error(&ar->e, stat); + // return ti_api_close_with_err(ar, &ar->e); + // TODO : return error + LOGC("HERE: %d", stat); + } + n = tmp_sz; + } + else + { + data = malloc(n); + if (data == NULL) + { + // TODO : return error + } + memcpy(data, src, n); + } + return api__close_resp(ar, data, n); +} diff --git a/src/siri/cfg/cfg.c b/src/siri/cfg/cfg.c index 1de320fc..8fa1861d 100644 --- a/src/siri/cfg/cfg.c +++ b/src/siri/cfg/cfg.c @@ -23,6 +23,7 @@ static siri_cfg_t siri_cfg = { .http_status_port=0, /* 0=disabled, 1-16535=enabled */ + .http_api_port=9020, /* 0=disabled, 1-16535=enabled */ .listen_client_port=9000, .listen_backend_port=9010, .bind_client_addr=NULL, diff --git a/src/siri/db/db.c b/src/siri/db/db.c index a9562660..fb2c4bf5 100644 --- a/src/siri/db/db.c +++ b/src/siri/db/db.c @@ -530,6 +530,28 @@ siridb_t * siridb_get(llist_t * siridb_list, const char * dbname) return NULL; } +/* + * Get a siridb object by name. + */ +siridb_t * siridb_getn(llist_t * siridb_list, const char * dbname, size_t n) +{ + llist_node_t * node = siridb_list->first; + siridb_t * siridb; + + while (node != NULL) + { + siridb = (siridb_t *) node->data; + if (n == strlen(siridb->dbname) && + strncmp(siridb->dbname, dbname, n) == 0) + { + return siridb; + } + node = node->next; + } + + return NULL; +} + /* * Get a siridb object by qpack name. */ diff --git a/src/siri/db/users.c b/src/siri/db/users.c index 85e5de45..1cc8ca0e 100644 --- a/src/siri/db/users.c +++ b/src/siri/db/users.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef __APPLE__ @@ -256,19 +257,26 @@ siridb_user_t * siridb_users_get_user_from_basic( { size_t size; char * b64 = base64_decode(data, n, &size); + siridb_user_t * user = NULL; - for (size_t nn = 0, end = size; n < end; ++nn) + for (size_t nn = 0, end = size; nn < end; ++nn) { if (b64[nn] == ':') { b64[nn] = '\0'; if (++nn > end) - return NULL; + break; - return siridb_users_get_user(siridb, b64, b64 + nn); + LOGC("User: %s Pass: %s", b64, b64 + nn); + + user = siridb_users_get_user(siridb, b64, b64 + nn); + break; } } + + free(b64); + return user; } /* diff --git a/src/siri/heartbeat.c b/src/siri/heartbeat.c index f4ff0dce..f0ed7780 100644 --- a/src/siri/heartbeat.c +++ b/src/siri/heartbeat.c @@ -84,6 +84,5 @@ static void HEARTBEAT_cb(uv_timer_t * handle __attribute__((unused))) siridb_node = siridb_node->next; } - } diff --git a/src/siri/net/pkg.c b/src/siri/net/pkg.c index 8ab559a8..103cb6d3 100644 --- a/src/siri/net/pkg.c +++ b/src/siri/net/pkg.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,13 @@ sirinet_pkg_t * sirinet_pkg_err( */ int sirinet_pkg_send(sirinet_stream_t * client, sirinet_pkg_t * pkg) { + if (client->tp == STREAM_API_CLIENT) + { + siri_api_send((siri_api_request_t *) client, pkg->data, pkg->len); + free(pkg); + return 0; + } + uv_write_t * req = malloc(sizeof(uv_write_t)); if (req == NULL) diff --git a/src/siri/net/stream.c b/src/siri/net/stream.c index 471bd452..7af4c6a7 100644 --- a/src/siri/net/stream.c +++ b/src/siri/net/stream.c @@ -140,6 +140,9 @@ void sirinet_stream_on_data( size_t total_sz; uint8_t check; + /* this functions should not be used for the API client */ + assert (client->tp != STREAM_API_CLIENT); + /* * client->on_data is NULL when 'sirinet_stream_decref' is called from * within this function. We should never call 'sirinet_stream_decref' twice diff --git a/src/siri/siri.c b/src/siri/siri.c index 6049816a..60bb1e26 100644 --- a/src/siri/siri.c +++ b/src/siri/siri.c @@ -514,10 +514,6 @@ static void SIRI_walk_close_handlers( { siri_health_close((siri_health_request_t *) handle->data); } - else if (siri_api_is_handle(handle)) - { - siri_api_close((siri_api_request_t *) handle->data); - } else { sirinet_stream_decref((sirinet_stream_t *) handle->data);